/*
 * kernellocks.h
 *
 *  Created on: Jun 10, 2011
 *      Author: peckb1
 *
 * Holds both the KernalLocks class for holding all of the Kernel locks
 * and the interactions with them, but also the Kernel Lock class itself
 *
 */

#ifndef KERNELLOCKS_H_
#define KERNELLOCKS_H_

#include <iostream>
#include <map>
#include "addrspace.h"
#include "list.h"
#include "synch.h"


class KernelLock {
    private:
        // pointer to the user program that controls this lock
        AddrSpace* _myAddrSpace;
        // the lock used underneath by the kernel
        Lock* _lock;
        // whether or not this lock has been deleted
        bool _isDeleted;
        // check to see if the lock was requested to be deleted, but was still in use
        bool _isToBeDeleted;
        // unique id for this lock
        int _id;
        // how many people are still waiting on the lock
        int _threadsWaiting;

    public:
        KernelLock(char* name, int UID, AddrSpace* _addrSpace);
        ~KernelLock();

        /*
         * Deletes the lock
         */
        void DeleteLock();

        /*
         * Sets the _isToBeDeleted flag to be true
         */
        void DeleteWhenReady();

        /*
         * Increments the number of threads waiting on this lock
         * - called when a new lock is acquired
         */
        void IncrementWaitingThreads();

        /*
         * Decrements the number of threads waiting on this lock
         * - called when a lock is being released
         */
        void DecrementWaitingThreads();

        /*
         * Returns the number of threads who called acquire on this lock and
         * are now waiting on the Lock object itself
         */
        int ThreadsWaiting();

        /*
         * Checks to see if this Lock is still active, to call acquire or release
         */
        bool IsActive();

        /*
         * Checks to see if Release can be called, but new Acquires
         * should be disallowed
         */
        bool IsToBeDeleted();

        /*
         * Returns the address space belonging to this Kernel Lock
         */
        AddrSpace* CurrentUserSpace();

        /*
         * Returns the lock being held by this Kernel Lock
         */
        Lock* GetLock();

};

class KernelCondition {
    private:
        // pointer to the user program that controls this lock
        AddrSpace* _myAddrSpace;
        // the condition used underneath by the kernel
        Condition* _condition;
        // whether or not this condition has been deleted
        bool _isDeleted;
        // check to see if the condition was requested to be deleted, but was still in use
        bool _isToBeDeleted;
        // unique id for this condition
        int _id;
        // how many people are still waiting on the condition
        int _threadsWaiting;

    public:
        KernelCondition(char* name, int UID, AddrSpace* _addrSpace);
        ~KernelCondition();

        /*
         * Deletes the lock
         */
        void DeleteCondition();

        /*
         * Sets the _isToBeDeleted flag to be true
         */
        void DeleteWhenReady();

        /*
         * Increments the number of threads waiting on this lock
         * - called when a new lock is Waiting
         */
        void IncrementWaitingThreads();

        /*
         * Decrements the number of threads waiting on this lock
         * - called when a lock is being Signaled
         */
        void DecrementWaitingThreads();

        /*
         * Clears the number of waiting threads
         * - called when a broadcast is needed
         */
        void ClearWaitingThreads();

        /*
         * Returns the number of threads who called acquire on this lock and
         * are now waiting on the Lock object itself
         */
        int ThreadsWaiting();

        /*
         * Checks to see if this Lock is still active, to call acquire or release
         */
        bool IsActive();

        /*
         * Checks to see if Signal/Broadcast can be called, but new Wait/Acquires
         * should be disallowed
         */
        bool IsToBeDeleted();

        /*
         * Returns the address space belonging to this Kernel Lock
         */
        AddrSpace* CurrentUserSpace();

        /*
         * Returns the Condition being held by this Kernel Lock
         */
        Condition* GetCondition();

};

class KernelLocks {
    private:
        // ****************************************************
        // Data for locks
        // ****************************************************

        // the id of the next lock that gets created
        int _currentNewLockId;

        /*
         * Map of each Lock we've created.
         * This allows us to easily gain information about any lock we have created before
         * - this allows us to reuse a lock index when a lock is called for deletion,
         *   but still be able to handle commands on a lock that has been deleted.
         */
        typedef std::map<int, KernelLock*> KernelLockMap;
        KernelLockMap _kernelLockMap;

        /*
         * A List of integers that is populated when a lock is deleted.
         * It contains the index in the _activeKernalLocks array of the place
         * we can reuse when asked to create a new lock
         */
        List* _kernelLockIndexToReUse;

        // the lock used to alter data about Kernel Locks
        Lock* _kernelLockTableLock;

        /**
         * Validates that a Lock is ready to be used by either Acquire, Release or destroyLock
         */
        bool ValidLockId(int lockId, char* task);
        bool ValidLockUserSpace(int lockId, AddrSpace* addrSpace, char* task);
        bool LockDeletionNotCalled(int LockId, char* task);
        bool LockActive(int lockId, char* task);
        /*
         * makes sure a lock is owned by the current thread
         */
        bool ProperOwner(int lockId, char* task);

        // ****************************************************
        // Data for Conditions
        // ****************************************************

        // the id of the next lock that gets created
        int _currentNewConditionId;

        /*
         * Map of each Lock we've created.
         * This allows us to easily gain information about any lock we have created before
         * - this allows us to reuse a lock index when a lock is called for deletion,
         *   but still be able to handle commands on a lock that has been deleted.
         */
        typedef std::map<int, KernelCondition*> KernelConditionMap;
        KernelConditionMap _kernelConditionMap;

        /*
         * A List of integers that is populated when a lock is deleted.
         * It contains the index in the _activeKernalLocks array of the place
         * we can reuse when asked to create a new lock
         */
        List* _kernelConditionIndexToReUse;

        // the lock used to alter data about Kernel Locks
        Lock* _kernelConditionTableLock;

        /**
         * Validates that a Condition is ready to be used by either Wait, Signal, Broadcast or DestroyCondition
         */
        bool ValidConditionId(int cvId, char* task);
        bool ValidConditionUserSpace(int cvId, AddrSpace* addrSpace, char* task);
        bool ConditionDeletionNotCalled(int cvId, char* task);
        bool ConditionActive(int cvId, char* task);

    public:
        KernelLocks();
        ~KernelLocks();

        // Methods to interact with Kernel Locks
        int CreateLock(char* lockName , AddrSpace* addrSpace);
        void Acquire(int lockId, AddrSpace* addrSpace);
        void Release(int lockId, AddrSpace* addrSpace);
        void DestroyLock(int lockId, AddrSpace* addrSpace);

        // Methods to interact with Kernel CVs
        int CreateCV(char* CVName, AddrSpace* addrSpace);
        void Wait(int CVid, int lockId, AddrSpace* addrSpace);
        void Signal(int CVid, int lockId, AddrSpace* addrSpace);
        void Broadcast(int CVid, int lockId, AddrSpace* addrSpace);
        void DestroyCV(int CVid, AddrSpace* addrSpace);
};


#endif /* KERNELLOCKS_H_ */
